package com.kaikai.test;

import org.apache.commons.lang3.CharUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;

public class SensitiveUtil {

    //替换符
    private static String REPLACEMENT = "***";

    //根节点
    private static TrieNode root;

    Map redisUtil = new HashMap();
    //redis中获取敏感词集合的key
    private static final String SENSITIVE_WORDS = "sensitiveWords";

    public static void main(String[] args) {
        SensitiveUtil util = new SensitiveUtil();
        List<String> filter = util.filter("来，咱们一起来赌博好不好，性感荷官在线发牌噢，快来试试水吧");
        System.out.printf(filter.toString());
    }

    public SensitiveUtil() {
        //初始化敏感词
        List<String> sensitiveWords = new ArrayList<>();
        sensitiveWords.add("赌博");
        sensitiveWords.add("试水");
        redisUtil.put(SENSITIVE_WORDS, sensitiveWords);

    }

    /**
     * @param text 待过滤的文本
     * @return java.util.List
     * @Description 返回敏感词字段集合 为空则返回null
     * @date 2021/11/12 10:45
     */
    public List<String> filter(String text) {
        try {
            //敏感词集合
            List<String> sensitiveWords = new ArrayList<>();
            sensitiveWords = (List<String>) redisUtil.get(SENSITIVE_WORDS);
            root = new TrieNode();
            for (String msgSensitiveWordName : sensitiveWords) {
                //将敏感词加入到前缀树中
                addKeyword(msgSensitiveWordName);
            }
            //真正的过滤阶段：返回结果集形式为map，包括过滤后的文本，以及敏感词汇集合
            Map<String, List<String>> result = getfilterResult(text);
            return result.get("text");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * @param text 待过滤文本
     * @return map {text=[过滤后的文本***], sensitiveWords=[我是敏感词]}
     * @Description 过滤敏感词
     */
    private static Map<String, List<String>> getfilterResult(String text) {
        if (StringUtils.isEmpty(text)) {
            return null;
        }
        //指针1  :指向root
        TrieNode tempNode = root;
        //指针2  :指向敏感词开头
        int begin = 0;
        //指针3  :指向敏感词后续字段
        int position = 0;
        //过滤结果
        StringBuilder sb = new StringBuilder();

        //敏感词集合
        List<String> sensitiveWords = new ArrayList<>();
        //返回结果
        Map<String, List<String>> resultMap = new HashMap<>();

        while (position < text.length()) {
            char c = text.charAt(position);
            //判断是否为符号，进行处理、防止用户插入特殊字符躲避敏感词检测
            if (isSymbol(c)) {
                if (tempNode == root) {
                    sb.append(c);
                    begin++;
                }
                position++;
                continue;
            }
            //检查下级节点
            tempNode = tempNode.getSubNode(c);
            if (tempNode == null) {
                sb.append(text.charAt(begin));
                position = ++begin;
                tempNode = root;
            } else if (tempNode.isKeywordEnd()) {
                //发现敏感词
                String sensitiveWord = text.substring(begin, position + 1);
                sensitiveWords.add(sensitiveWord);
                sb.append(REPLACEMENT);
                begin = ++position;
                tempNode = root;
            } else {
                position++;
            }
        }
        //将最后一批字符计入结果
        sb.append(text.substring(begin));
        //过滤后的文本
        resultMap.put("text", Arrays.asList(sb.toString()));
        resultMap.put(SENSITIVE_WORDS, sensitiveWords);
        return resultMap;
    }


    /**
     * @Description 判断是否为符号
     * @date 2021/11/16 9:33
     */
    private static boolean isSymbol(Character c) {
    /**
     * CharUtils 可引入
     *       <dependency>
     *             <groupId>org.apache.commons</groupId>
     *             <artifactId>commons-lang</artifactId>
     *         </dependency>
     */
        return !CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF);
    }


    /**
     * @param keyword
     * @return void
     * @Description 将敏感词添加到前缀树当中
     */
    private static void addKeyword(String keyword) {
        TrieNode tempNode = root;
        for (int i = 0; i < keyword.length(); i++) {
            char c = keyword.charAt(i);
            TrieNode subNode = tempNode.getSubNode(c);
            if (subNode == null) {
                //初始化子节点
                subNode = new TrieNode();
                tempNode.addSubNode(c, subNode);
            }
            //指向子节点，进入下一轮循环
            tempNode = subNode;

            //设置结束标识
            if (i == keyword.length() - 1) {
                tempNode.setKeywordEnd(true);
            }
        }
    }


    /**
     * 前缀树
     */
    public static class TrieNode {

        private boolean isKeywordEnd = false;

        private Map<Character, TrieNode> subNodes = new HashMap<>();

        public boolean isKeywordEnd() {
            return isKeywordEnd;
        }

        public void setKeywordEnd(boolean keywordEnd) {
            isKeywordEnd = keywordEnd;
        }

        public void addSubNode(Character key, TrieNode value) {
            subNodes.put(key, value);
        }

        public TrieNode getSubNode(Character key) {
            return subNodes.get(key);
        }
    }


}


